package com.tanhua.server.service;

import cn.hutool.core.collection.CollUtil;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.constants.Constants;
import com.tanhua.commons.exception.TanHuaException;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.CommentApi;
import com.tanhua.dubbo.api.mongo.MovementApi;
import com.tanhua.dubbo.api.mongo.VisitorApi;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.enums.CommentType;
import com.tanhua.model.mongo.Comment;
import com.tanhua.model.mongo.Movement;
import com.tanhua.model.mongo.Visitors;
import com.tanhua.model.vo.*;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 圈子-业务处理层
 */
@Service
@Slf4j
public class MovementService {

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private MovementApi movementApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private CommentApi commentApi;

    @DubboReference
    private VisitorApi visitorApi;

    /**
     * 圈子-发布动态
     *
     * @param movementVo
     * @param imageContent
     */
    public void addMovement(MovementVo movementVo, MultipartFile[] imageContent) {
        try {
            Long userId = UserHolder.getUserId();
            List<String> listMedias = new ArrayList<>();
            //1 文件上传阿里云 得到图片地址集合
            if (imageContent != null) {
                for (MultipartFile multipartFile : imageContent) {
                    String originalFilename = multipartFile.getOriginalFilename();
                    listMedias.add(ossTemplate.upload(originalFilename, multipartFile.getInputStream()));
                }
            }
            //2 构造Movement对象
            Movement movement = new Movement();  //id(自动生成) pid(推荐系统pid) created(发布时间)
            BeanUtils.copyProperties(movementVo, movement);//动态内容 经纬度
            movement.setUserId(userId);//发布动态用户id
            movement.setLocationName(movementVo.getLocation());//位置名称
            movement.setMedias(listMedias);
            //3 调用服务发布动态
            movementApi.addMovement(movement);
        } catch (IOException e) {
            log.error("发布动态失败了" + e.getMessage());
            throw new TanHuaException(ErrorResult.error());
        }

    }

    /**
     * 圈子-个人动态（我的动态 首页某个佳人动态数据）
     */
    public PageResult<MovementsVo> findPageMovement(Long page, Long pageSize, Long userId) {
        //1根据用户id分页查询动态数据（Movement）
        PageResult<Movement> movementPageResult = movementApi.findPageMovement(page, pageSize, userId);
        if(CollectionUtils.isEmpty(movementPageResult.getItems())){
            return null;//这样有可能有问题
        }
        //2根据用户id查询用户信息 tb_user_info表
        UserInfo userInfo = userInfoApi.findUserInfo(userId);
        //3循环遍历动态数据 基于动态数据与用户信息构造Vo返回
        List<MovementsVo> movementsVoList = new ArrayList<>();
        for (Movement movement : movementPageResult.getItems()) {
            movementsVoList.add(MovementsVo.init(userInfo,movement));
        }
        return new PageResult<>(page,pageSize,movementPageResult.getCounts(),movementsVoList);
    }

    /**
     * 好友动态(动态表 好友表 好友时间线表)
     */
    public PageResult<MovementsVo> findFriendPageMovement(Long page, Long pageSize) {
        Long userId = UserHolder.getUserId();//当前用户id
        //1.根据当前用户id分页查询时间线 动态表分页数据
        PageResult<Movement> movementPageResult = movementApi.findFriendPageMovement(page,pageSize,userId);
        if(CollectionUtils.isEmpty(movementPageResult.getItems())){
            return null;
        }
        //2.获取动态的所有作者用户ids
        List<Movement> movementList = movementPageResult.getItems();
        //方式一：
        //List<Long> userIds = CollUtil.getFieldValues(movementList, "userId", Long.class);
        List<MovementsVo> movementsVoList = getMovementsVos(movementList);
        return new PageResult<>(page,pageSize,movementPageResult.getCounts(),movementsVoList);
    }

    /**
     * 根据动态集合数据获取Vo
     * @param movementList
     * @return
     */
    private List<MovementsVo> getMovementsVos(List<Movement> movementList) {
        //方式二：
        List<Long> userIds = movementList.stream().map(Movement::getUserId).collect(Collectors.toList());
        //3.根据所有作者用户ids查询用户信息tb_user_info表
        Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(userIds, null);
        //4.基于动态数据和用户信息 构造Vo返回
        List<MovementsVo> movementsVoList = new ArrayList<>();
        for (Movement movement : movementList) {
            UserInfo userInfo = userInfoMap.get(movement.getUserId());
            MovementsVo vo = MovementsVo.init(userInfo, movement);
            //处理是否点赞
            String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();// key:String value:hash
            String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();//不同业务类型+不同的用户id
            if(!StringUtils.isEmpty(stringRedisTemplate.opsForHash().get(key,hashKey))){
                vo.setHasLiked(1);//已经点赞
            }
            movementsVoList.add(vo);
        }
        return movementsVoList;
    }

    /**
     * 推荐动态
     */
    public PageResult<MovementsVo> findRecommendPageMovement(Long page, Long pageSize) {
        //1.根据 Constants.MOVEMENTS_RECOMMEND + 登录用户id 查询redis中Pids
        String key = Constants.MOVEMENTS_RECOMMEND + UserHolder.getUserId();//key:MOVEMENTS_RECOMMEND_2
        String pids = stringRedisTemplate.opsForValue().get(key);//value值：3,4,5,6,7,8,9,10(动态表中pid)
        List<Movement> movementList = new ArrayList<Movement>();
        long total = 0l;
        //2.Pids如果没有值随机查询10个动态
        if(StringUtils.isEmpty(pids)){
            movementList = movementApi.randomMovement();
            total = movementList.size();
        }else {
            //3.Pids如果有值 将Pids分页处理 得到需要展示的Pids值
            String[] pidStrs = pids.split(",");//假设1000个pids
            long start = (page - 1) * pageSize; //1000
            if(start<pidStrs.length) {
                //3.1得到10个Pids
                //List<Long> pidList = Arrays.stream(pidStrs).skip(start).limit(pageSize).map(idStr -> Long.valueOf(idStr)).collect(Collectors.toList());
                //List<Long> pidList = Arrays.stream(pidStrs).skip(start).limit(pageSize).map(Long::getLong).collect(Collectors.toList());
                List<Long> pidList = Arrays.stream(pidStrs).skip(start).limit(pageSize).map(Long::valueOf).collect(Collectors.toList());
                log.debug("*****************************************"+pidList.toString());
                //4.根据Pids值分页查询动态数据
                movementList = movementApi.findByPids(pidList);
            }
            total = pidStrs.length;
        }
        //5.获取动态数据中作者ids查询作者信息
        //6.基于动态数据和作者信息构造Vo返回
        List<MovementsVo> movementsVoList = getMovementsVos(movementList);
        return new PageResult<>(page,pageSize,total,movementsVoList);
    }

    /**
     * 单条动态
     */
    public MovementsVo findMovement(String publishId) {
        //1根据动态id查询动态数据
        Movement movement = movementApi.findById(publishId);
        //2获取动态作者信息
        Long userId = movement.getUserId();
        UserInfo userInfo = userInfoApi.findUserInfo(userId);
        //3.基于动态数据与用户信息构造vo
        return MovementsVo.init(userInfo, movement);
    }

    /**
     * 动态点赞
     * publishId:动态id
     * @return
     */
    public Integer like(String publishId) {
        Long userId = UserHolder.getUserId();
        //1构造评论对象调用服务添加点赞记录
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));//动态id
        comment.setCommentType(CommentType.LIKE.getType());//评论类型，1-点赞，2-评论，3-喜欢
        comment.setUserId(userId);//评论人
        Integer count = commentApi.addComment(comment); //返回点赞数量
        //2将点赞记录写入redis key value形式
        String key = Constants.MOVEMENTS_INTERACT_KEY + publishId;// key:String value:hash
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();//不同业务类型+不同的用户id
        stringRedisTemplate.opsForHash().put(key,hashKey,"1");
        return  count;
    }


    /**
     * 动态取消点赞
     * @return
     */
    public Integer dislike(String publishId) {
        Long userId = UserHolder.getUserId();
        //1构造评论对象调用服务删除点赞记录
        Comment comment = new Comment();
        comment.setPublishId(new ObjectId(publishId));//动态id
        comment.setCommentType(CommentType.LIKE.getType());//评论类型，1-点赞，2-评论，3-喜欢
        comment.setUserId(userId);//评论人
        Integer count = commentApi.deleteComment(comment); //返回点赞数量
        //2将点赞记录从redis删除
        String key = Constants.MOVEMENTS_INTERACT_KEY + publishId;// key:String value:hash
        String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + UserHolder.getUserId();//不同业务类型+不同的用户id
        stringRedisTemplate.opsForHash().delete(key,hashKey);
        return count;
    }

    /**
     * 首页-我的访客
     * @return
     */
    public List<VisitorsVo> findvisitors() {
        Long userId = UserHolder.getUserId();
        //1. redis的key, hash 所有用户的访客时间都记录这个hash集合里
        String key = Constants.VISITORS_USER;
        //2. whoKey,登录用户id
        String whoKey = UserHolder.getUserId().toString();
        //3.根据登录用户id查询redis访客记录
        String lastTimeStr = (String)stringRedisTemplate.opsForHash().get(key, whoKey);
        // 时间戳字符串转成long类型，visitor集合中的date是long类型 2022-02-11 12:00:00
        Long lastTime = lastTimeStr==null?null:Long.valueOf(lastTimeStr);
        //4.调用服务获取5条记录
        List<Visitors> visitorsList = visitorApi.findvisitors(userId,lastTime);
        List<VisitorsVo> visitorsVoList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(visitorsList)){
            //4.1获取所有访客用户ids
            List<Long> visitorUserIds = visitorsList.stream().map(Visitors::getVisitorUserId).collect(Collectors.toList());
            //4.2获取所有访客用户信息
            Map<Long, UserInfo> userInfoMap = userInfoApi.findByIds(visitorUserIds,null);
            for (Visitors visitors : visitorsList) {
                //5.构造vo返回
                visitorsVoList.add(VisitorsVo.init(userInfoMap.get(visitors.getVisitorUserId()),visitors));
            }
        }
        return visitorsVoList;
    }
}
